﻿using SlimDX;

namespace BasicFramework.Services.MeshLoader.Nodes
{
    public class SkinnedTangentVertex
    {
        /// <summary>
        /// Position
        /// </summary>
        public Vector3 pos;

        /// <summary>
        /// 3 weights of each bone (often just 1, 0, 0 to use only 1 bone)
        /// </summary>
        public Vector3 blendWeights;
        /// <summary>
        /// Indices for used bones. Just floats because shader expect that and
        /// we can't use UByte4 for lower than vs_2_0 hardware. Uses just int
        /// values really.
        /// </summary>
        public Vector3 blendIndices;
        /// <summary>
        /// Texture coordinates
        /// </summary>
        public Vector2 uv;
        /// <summary>
        /// Normal
        /// </summary>
        public Vector3 normal;
        /// <summary>
        /// Tangent
        /// </summary>
        public Vector3 tangent;
        /// <summary>
        /// Stride size, in XNA called SizeInBytes. I'm just conforming with that.
        /// Btw: How is this supposed to work without using unsafe AND
        /// without using System.Runtime.InteropServices.Marshal.SizeOf?
        /// </summary>
        public static int SizeInBytes
        {
            get
            {
                // 4 bytes per float:
                // 3 floats pos, 3 for the blend weights and 3 for the blend indices,
                // 2 floats uv, 3 floats normal and 3 float tangent.
                return 4 * (3 + 3 + 3 + 2 + 3 + 3);
            } // get
        } // SizeInBytes

        /// <summary>
        /// U texture coordinate
        /// </summary>
        /// <returns>Float</returns>
        public float U
        {
            get
            {
                return uv.X;
            } // get
        } // U

        /// <summary>
        /// V texture coordinate
        /// </summary>
        /// <returns>Float</returns>
        public float V
        {
            get
            {
                return uv.Y;
            } // get
        } // V


        /// <summary>

        public SkinnedTangentVertex(Vector3 setPos, Vector3 setBlendWeights, Vector3 setBlendIndices, float setU, float setV, Vector3 setNormal, Vector3 setTangent)//, Vector3 setBinormal)
        {
            pos = setPos;
            blendWeights = setBlendWeights;
            blendIndices = setBlendIndices;
            uv = new Vector2(setU, setV);
            normal = setNormal;
            tangent = setTangent;
        }

        public SkinnedTangentVertex(Vector3 setPos, Vector3 setBlendWeights, Vector3 setBlendIndices, Vector2 setUv, Vector3 setNormal, Vector3 setTangent)
        {
            pos = setPos;
            blendWeights = setBlendWeights;
            blendIndices = setBlendIndices;
            uv = setUv;
            normal = setNormal;
            tangent = setTangent;
        }

        public override string ToString()
        {
            return "SkinnedTangentVertex(pos=" + pos + ", " +
                "blendWeights=" + blendWeights + ", " +
                "blendIndices=" + blendIndices + ", " +
                "u=" + uv.X + ", " +
                "v=" + uv.Y + ", " +
                "normal=" + normal + ", " +
                "tangent=" + tangent + ")";
        }

        public static bool NearlyEquals(SkinnedTangentVertex a, SkinnedTangentVertex b)
        {
            //SkinningWithColladaModelsInXna.Helpers.Log.Write("Compare a=" + a.pos + ", " + a.uv + ", "+a.normal+
            //  " with b=" + b.pos + ", " + b.uv+ ", "+b.normal);
            //return false;
            // Position has to match, else it is just different vertex
            return a.pos == b.pos &&
                // Ignore blend indices and blend weights, they are the same
                // anyway, because they are calculated from the bone distances.
                System.Math.Abs(a.uv.X - b.uv.X) < 0.001f &&
                System.Math.Abs(a.uv.Y - b.uv.Y) < 0.001f &&
                // Normals and tangents do not have to be very close, we can't see
                // any difference between small variations here, but by optimizing
                // similar vertices we can improve the overall rendering performance.
                (a.normal - b.normal).Length() < 0.1f &&
                (a.tangent - b.tangent).Length() < 0.1f;
            //SkinningWithColladaModelsInXna.Helpers.Log.Write("ret=" + ret);
            //			return ret;
        } 
    }
}
